#!/usr/bin/env python3
import numpy as np
from functools import reduce

"""
函数说明：创建数据
param：
	无
returns：
	postingList - 实验样本切分的词条
	classVec - 类别标签向量
"""
def loadDataSet():
	#数据集
	postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
	['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
	['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
	['stop', 'posting', 'stupid', 'worthless', 'garbage'],
	['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
	['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
	#每个数据集的标签（0：非侮辱类，1：侮辱类别）
	classVec = [0,1,0,1,0,1]
	return postingList,classVec

"""
函数说明：将实验样本整理成为不重复的词条列表，也就是词汇表
param：
	dataSet - 数据集
returns:
	vocabList - 整理后的词汇表
"""
def createVocabList(dataSet):
	vocabList = set([])	#创建一个空的不循环的列表
	for each in dataSet:
		vocabList = vocabList | set(each)	#取得vocabList和dataSet中所有数据的并集
		# print(vocabList)
	return list(vocabList)	#返回的是list

"""
函数说明：将dataSet数据集全部向量化为0，1数据
param:
	vocabList - 字典，也就是词汇表
	inputSet - 数据集数据List
return:
	returnVec - 将数据集全部向量化后的数据集
"""
def setOfWords2Vec(vocabList,inputSet):
	returnVec = [0] * len(vocabList)	#形成[0 * len（vocabList）这个长度的returnVec]
	for word in inputSet:				#最后返回的是这一行所有单词在vocabList中分别处于哪个位置
		if word in vocabList:	#判断是否存在于集合中
			returnVec[vocabList.index(word)] = 1
		else:
			print("the word:%s not in vocabulary!" % (word))
	return returnVec

"""
函数说明：将向量化后的trainMat使用朴素贝叶斯来训练
param：
	trainMat - 向量化后的数据
	classVec - 识别是否侮辱的标签
"""
def trainNB0(trainMat,classVec):
	numTrainDocs = len(trainMat)	#训练的文档数目
	numWords = len(trainMat[0])	#计算每篇文档的词条数目
	pAbusive = sum(classVec) / float(len(classVec))	#计算侮辱类文档的概率
	p0Num = np.ones(numWords)	#创建np.zeros数组，初始值全为0，长度为每篇文档的此条数相同
	p1Num = np.ones(numWords)
	p0Denom = 2	#计算非侮辱性时候出现在词条的数目,并且启用拉普拉斯平滑
	p1Denom = 2	#计算侮辱性时候出现在词条的数目
	for i in range(numTrainDocs):	#遍历每条评论
		if classVec[i] == 1:	#若是为侮辱性评论
			p1Num += trainMat[i]
			p1Denom += sum(trainMat[i])
		else:
			p0Num += trainMat[i]
			p0Denom += sum(trainMat[i])
	p1Vect = np.log(p1Num / p1Denom)	#侮辱性的条件概率
	p0Vect = np.log(p0Num / p0Denom)	#非侮辱性条件概率
	return	p1Vect,p0Vect,pAbusive

"""
函数说明：朴素贝叶斯分类函数
param:
	vec2Classfy - 待分类的词条数组
	p0Vec - 非侮辱性的条件概率数组
	p1Vec - 侮辱性的条件概率数据
	pClass - 文档属于侮辱类的概率
return:
	0 - 属于非侮辱类
	1 - 属于侮辱类
"""
def classfyNB(vec2Classfy,p0Vec,p1Vec,pClass):
	# p1 = reduce(lambda x,y:x*y,vec2Classfy * p1Vec) * pClass
	# p0 = reduce(lambda x,y:x*y,vec2Classfy * p1Vec) * (1.0 - pClass)
	p1 = sum(vec2Classfy * p1Vec) + np.log(pClass)
	p0 = sum(vec2Classfy * p0Vec) + np.log(1.0 - pClass)
	print("p1:",p1)
	print("p0:",p0)
	if p1 > p0:
		return 1
	else :
		return 0

"""
函数说明：测试贝叶斯分类器
param:
	无
return:
	无
"""
def testNB():
	postingList,classVec = loadDataSet()
	# print(postingList)
	vocabList = createVocabList(postingList)
	# print(vocabList)
	trainMat = []
	for postinDoc in postingList:
		trainMat.append(setOfWords2Vec(vocabList,postinDoc))
	# print(trainMat)
	p1Vect,p0Vect,pClass = trainNB0(trainMat,classVec)
	# print(vocabList)
	# print(p1Vect)
	# print("~~~~~~~~~~~~")
	# print(p0Vect)
	# print("~~~~~~~~~~~~")
	# print(pClass)
	# testEntry = ['he','test']	#测试样本数据
	testEntry = ['stupid', 'garbage']
	testDoc = np.array(setOfWords2Vec(vocabList,testEntry))	#向量化测试样本数据
	if classfyNB(testDoc,p0Vect,p1Vect,pClass):
		print(testEntry,"属于侮辱类")
	else:
		print(testEntry,"属于非侮辱类")

if __name__ == '__main__':
	testNB()
